--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
meshchatx/src/backend/markdown_renderer.py fda9187e95d8b9cc8373c1de23cefce6928c241d (fda9187e) Text, 6.81 KB
Tff7b72import T7ee787html
Tff7b72import T7ee787re
Tff7b72class T56d364MarkdownRendererTb4b4b4:
T8b949e"""A simple Markdown to HTML renderer."""
Tf0883e@staticmethod
Tff7b72def Td2a8ffrenderTb4b4b4(Te6edf3textTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3textTb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff"
T8b949e# Escape HTML entities first to prevent XSS
T8b949e# Use a more limited escape if we want to allow some things,
T8b949e# but for docs, full escape is safest.
Te6edf3text Tff7b72= Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3textTb4b4b4)
T8b949e# Fenced code blocks - process these FIRST and replace with placeholders
T8b949e# to avoid other regexes mangling the code content
Te6edf3code_blocks Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ffcode_block_placeholderTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3lang Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"
Te6edf3code Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff2Tb4b4b4)
Te6edf3placeholder Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ff[[CBTffd700{Tffa657lenTb4b4b4(Te6edf3code_blocksTb4b4b4)Tffd700}Ta5d6ff]]Ta5d6ff"
Te6edf3code_blocksTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<pre class=Ta5d6ff"Ta5d6ffbg-gray-800 dark:bg-zinc-900 text-zinc-100 dark:text-zinc-100 p-4 rounded-lg my-4 overflow-x-auto border border-gray-700 dark:border-zinc-800 font-mono text-smTa5d6ff"Ta5d6ff><code class=Ta5d6ff"Ta5d6fflanguage-Tffd700{Te6edf3langTffd700}Ta5d6ff text-inheritTa5d6ff"Ta5d6ff>Tffd700{Te6edf3codeTffd700}Ta5d6ff</code></pre>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3placeholder
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff```(Ta5d6ff\Ta5d6ffw+)?Ta5d6ff\Ta5d6ffn(.*?)Ta5d6ff\Ta5d6ffn```Ta5d6ff"Tb4b4b4,
Te6edf3code_block_placeholderTb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffDOTALLTb4b4b4,
Tb4b4b4)
T8b949e# Horizontal Rules
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^---+$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<hr class=Ta5d6ff"Ta5d6ffmy-8 border-t border-gray-200 dark:border-zinc-800Ta5d6ff"Ta5d6ff>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Headers
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^# (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<h1 class=Ta5d6ff"Ta5d6fftext-3xl font-bold mt-8 mb-4 text-gray-900 dark:text-zinc-100Ta5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</h1>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^## (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<h2 class=Ta5d6ff"Ta5d6fftext-2xl font-bold mt-6 mb-3 text-gray-900 dark:text-zinc-100Ta5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</h2>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^### (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<h3 class=Ta5d6ff"Ta5d6fftext-xl font-bold mt-4 mb-2 text-gray-900 dark:text-zinc-100Ta5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</h3>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^#### (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<h4 class=Ta5d6ff"Ta5d6fftext-lg font-bold mt-3 mb-2 text-gray-900 dark:text-zinc-100Ta5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</h4>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Bold and Italic
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*(.*?)Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<strong><em>Ta5d6ff\Ta5d6ff1</em></strong>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*(.*?)Ta5d6ff\Ta5d6ff*Ta5d6ff\Ta5d6ff*Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<strong>Ta5d6ff\Ta5d6ff1</strong>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff*(.*?)Ta5d6ff\Ta5d6ff*Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<em>Ta5d6ff\Ta5d6ff1</em>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff___(.*?)___Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<strong><em>Ta5d6ff\Ta5d6ff1</em></strong>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff__(.*?)__Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<strong>Ta5d6ff\Ta5d6ff1</strong>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff_(.*?)_Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<em>Ta5d6ff\Ta5d6ff1</em>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
T8b949e# Strikethrough
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff~~(.*?)~~Ta5d6ff"Tb4b4b4, Ta5d6ffrTa5d6ff"Ta5d6ff<del>Ta5d6ff\Ta5d6ff1</del>Ta5d6ff"Tb4b4b4, Te6edf3textTb4b4b4)
T8b949e# Inline code
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff`([^`]+)`Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<code class=Ta5d6ff"Ta5d6ffbg-gray-100 dark:bg-zinc-800 px-1.5 py-0.5 rounded text-pink-600 dark:text-pink-400 font-mono text-[0.9em]Ta5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</code>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Tb4b4b4)
T8b949e# Task lists
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^[-*] Ta5d6ff\Ta5d6ff[ Ta5d6ff\Ta5d6ff] (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffflex items-start gap-2 list-noneTa5d6ff"Ta5d6ff><input type=Ta5d6ff"Ta5d6ffcheckboxTa5d6ff"Ta5d6ff disabled class=Ta5d6ff"Ta5d6ffmt-1Ta5d6ff"Ta5d6ff> <span>Ta5d6ff\Ta5d6ff1</span></li>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^[-*] Ta5d6ff\Ta5d6ff[xTa5d6ff\Ta5d6ff] (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffflex items-start gap-2 list-noneTa5d6ff"Ta5d6ff><input type=Ta5d6ff"Ta5d6ffcheckboxTa5d6ff"Ta5d6ff checked disabled class=Ta5d6ff"Ta5d6ffmt-1Ta5d6ff"Ta5d6ff> <span class=Ta5d6ff"Ta5d6ffline-through opacity-50Ta5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</span></li>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Links
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff\Ta5d6ff(([^)]+)Ta5d6ff\Ta5d6ff)Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<a href=Ta5d6ff"Ta5d6ff\Ta5d6ff2Ta5d6ff"Ta5d6ff class=Ta5d6ff"Ta5d6fftext-blue-600 dark:text-blue-400 hover:underlineTa5d6ff"Ta5d6ff target=Ta5d6ff"Ta5d6ff_blankTa5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</a>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Tb4b4b4)
T8b949e# Images
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff!Ta5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]*)Ta5d6ff\Ta5d6ff]Ta5d6ff\Ta5d6ff(([^)]+)Ta5d6ff\Ta5d6ff)Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<div class=Ta5d6ff"Ta5d6ffmy-6Ta5d6ff"Ta5d6ff><img src=Ta5d6ff"Ta5d6ff\Ta5d6ff2Ta5d6ff"Ta5d6ff alt=Ta5d6ff"Ta5d6ff\Ta5d6ff1Ta5d6ff"Ta5d6ff class=Ta5d6ff"Ta5d6ffmax-w-full h-auto rounded-xl shadow-lg border border-gray-100 dark:border-zinc-800Ta5d6ff"Ta5d6ff></div>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Tb4b4b4)
T8b949e# Blockquotes
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff^> (.*)$Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff'Ta5d6ff<blockquote class=Ta5d6ff"Ta5d6ffborder-l-4 border-blue-500/50 pl-4 py-2 my-6 italic bg-gray-50 dark:bg-zinc-900/50 text-gray-700 dark:text-zinc-300 rounded-r-lgTa5d6ff"Ta5d6ff>Ta5d6ff\Ta5d6ff1</blockquote>Ta5d6ff'Tb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Lists - Simple single level for now to keep it predictable
Tff7b72def Td2a8ffunordered_list_replTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3items Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff0Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4)
Te6edf3html_items Tff7b72= Ta5d6ff"Ta5d6ff"
Tff7b72for Te6edf3i Tff7b72in Te6edf3itemsTb4b4b4:
T8b949e# Check if it's already a task list item
Tff7b72if Ta5d6ff'Ta5d6fftype=Ta5d6ff"Ta5d6ffcheckboxTa5d6ff"Ta5d6ff' Tff7b72in Te6edf3iTb4b4b4:
Te6edf3html_items Tff7b72+Tff7b72= Te6edf3i
Tff7b72elseTb4b4b4:
Te6edf3content Tff7b72= Te6edf3iTb4b4b4[T79c0ff2Tb4b4b4:Tb4b4b4]Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Te6edf3html_items Tff7b72+Tff7b72= Ta5d6fffTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffml-4 mb-1 list-disc text-gray-700 dark:text-zinc-300Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3contentTffd700}Ta5d6ff</li>Ta5d6ff'
Tff7b72return Ta5d6fffTa5d6ff'Ta5d6ff<ul class=Ta5d6ff"Ta5d6ffmy-4 space-y-1Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3html_itemsTffd700}Ta5d6ff</ul>Ta5d6ff'
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff((?:^[*-] .*Ta5d6ff\Ta5d6ffn?)+)Ta5d6ff"Tb4b4b4,
Te6edf3unordered_list_replTb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8ffordered_list_replTb4b4b4(Te6edf3matchTb4b4b4)Tb4b4b4:
Te6edf3items Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff0Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4)
Te6edf3html_items Tff7b72= Ta5d6ff"Ta5d6ff"
Tff7b72for Te6edf3i Tff7b72in Te6edf3itemsTb4b4b4:
Te6edf3content Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff^Ta5d6ff\Ta5d6ffd+Ta5d6ff\Ta5d6ff. Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3iTb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Te6edf3html_items Tff7b72+Tff7b72= Ta5d6fffTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffml-4 mb-1 list-decimal text-gray-700 dark:text-zinc-300Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3contentTffd700}Ta5d6ff</li>Ta5d6ff'
Tff7b72return Ta5d6fffTa5d6ff'Ta5d6ff<ol class=Ta5d6ff"Ta5d6ffmy-4 space-y-1Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3html_itemsTffd700}Ta5d6ff</ol>Ta5d6ff'
Te6edf3text Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff((?:^Ta5d6ff\Ta5d6ffd+Ta5d6ff\Ta5d6ff. .*Ta5d6ff\Ta5d6ffn?)+)Ta5d6ff"Tb4b4b4,
Te6edf3ordered_list_replTb4b4b4,
Te6edf3textTb4b4b4,
Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffMULTILINETb4b4b4,
Tb4b4b4)
T8b949e# Paragraphs - double newline to p tag
Te6edf3parts Tff7b72= Te6edf3textTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Tffea00\nTffea00\nTa5d6ff"Tb4b4b4)
Te6edf3processed_parts Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3part Tff7b72in Te6edf3partsTb4b4b4:
Te6edf3part Tff7b72= Te6edf3partTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3partTb4b4b4:
Tff7b72continue
T8b949e# If it's a placeholder for code block, don't wrap in <p>
Tff7b72if Te6edf3partTff7b72.Td2a8ffstartswithTb4b4b4(Ta5d6ff"Ta5d6ff[[CBTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3partTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff]]Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3processed_partsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3partTb4b4b4)
Tff7b72continue
T8b949e# If it already starts with a block tag, don't wrap in <p>
Tff7b72if Te6edf3reTff7b72.Td2a8ffmatchTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff^<(hTa5d6ff\Ta5d6ffd|ul|ol|li|blockquote|hr|div)Ta5d6ff"Tb4b4b4, Te6edf3partTb4b4b4)Tb4b4b4:
Te6edf3processed_partsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3partTb4b4b4)
Tff7b72elseTb4b4b4:
T8b949e# Replace single newlines with <br> for line breaks within paragraphs
Te6edf3part Tff7b72= Te6edf3partTff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff<br>Ta5d6ff"Tb4b4b4)
Te6edf3processed_partsTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<p class=Ta5d6ff"Ta5d6ffmy-4 leading-relaxed text-gray-800 dark:text-zinc-200Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3partTffd700}Ta5d6ff</p>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Te6edf3text Tff7b72= Ta5d6ff"Tffea00\nTa5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3processed_partsTb4b4b4)
T8b949e# Restore code blocks
Tff7b72for Te6edf3iTb4b4b4, Te6edf3code_html Tff7b72in Tffa657enumerateTb4b4b4(Te6edf3code_blocksTb4b4b4)Tb4b4b4:
Te6edf3text Tff7b72= Te6edf3textTff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff[[CBTffd700{Te6edf3iTffd700}Ta5d6ff]]Ta5d6ff"Tb4b4b4, Te6edf3code_htmlTb4b4b4)
Tff7b72return Te6edf3text
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────